import React, { Component, createRef } from 'react'
import { connect } from 'react-redux'
import { message } from 'antd'

import { createANewDrawing, createANewErasing } from '../redux/action/freeDrawingActions'

import { settings, backX, backY, reloadSettings } from '../js/draw'

// need to be deleted
window.style = {
	color: '#61dafb',
}

let mouseDown = false,
	wasIn = false,
	lastX = 0,
	lastY = 0,
	multiple = 1

function floorX(x) {
	// 将x值减去偏移量，使其靠近原来格点所在位置
	x -= settings.O.offsetLeft % settings.unit
	// 用原来的格点位置计算后加回偏移量
	return Math.floor(x / settings.unit) * settings.unit + (settings.O.offsetLeft % settings.unit)
}
function ceilX(x) {
	x -= settings.O.offsetLeft % settings.unit
	return Math.ceil(x / settings.unit) * settings.unit + (settings.O.offsetLeft % settings.unit)
}
function floorY(y) {
	y -= settings.O.offsetTop % settings.unit
	return Math.floor(y / settings.unit) * settings.unit + (settings.O.offsetTop % settings.unit)
}
function ceilY(y) {
	y -= settings.O.offsetTop % settings.unit
	return Math.ceil(y / settings.unit) * settings.unit + (settings.O.offsetTop % settings.unit)
}

function inErrRanger(x, y, errRange) {
	let xIn = false,
		yIn = false,
		correctX,
		correctY
	if (Math.abs(x - floorX(x)) < errRange) {
		xIn = true
		correctX = floorX(x)
	} else if (Math.abs(x - ceilX(x)) < errRange) {
		xIn = true
		correctX = ceilX(x)
	}
	if (Math.abs(y - floorY(y)) < errRange) {
		yIn = true
		correctY = floorY(y)
	} else if (Math.abs(y - ceilY(y)) < errRange) {
		yIn = true
		correctY = ceilY(y)
	}
	return {
		inRange: xIn && yIn,
		x: correctX,
		y: correctY,
	}
}
function db(fn, delay, args = []) {
	let timeout
	return function (event) {
		if (timeout) clearTimeout(timeout)
		timeout = setTimeout(fn, delay, ...args, event)
	}
}
class CtrlLayer extends Component {
	constructor(props) {
		super(props)
		this.locateFrame = createRef()
		this.state = {
			show: false,
			x: 0,
			y: 0,
			formatX: 0,
			formatY: 0,
			winShow: false,
		}
	}
	closeWin = () => {
		this.setState({ winShow: false })
	}
	showWin = () => {
		this.setState({ winShow: true })
	}
	closeDb = db(close => close(), 1500, [this.closeWin])
	showDb = db(
		(show, close) => {
			show()
			close()
		},
		500,
		[this.showWin, this.closeDb]
	)
	showMagneticPoint = e => {
		this.closeWin()
		const { offsetLeft, offsetTop, clientWidth, clientHeight } = this.locateFrame.current
		if (
			e.clientX > offsetLeft + clientWidth ||
			e.clientX < offsetLeft ||
			e.clientY > offsetTop + clientHeight ||
			e.clientY < offsetTop
		) {
			this.setState({
				show: false,
			})
			return false
		}
		// 容错率
		const errRange = settings.unit / 2
		const { x, y, inRange } = inErrRanger(e.clientX - offsetLeft, e.clientY - offsetTop, errRange)
		if (inRange) {
			this.setState({
				x: x + offsetLeft,
				y: y + offsetTop,
				formatX: x,
				formatY: y,
			})
			this.showDb()
		}
	}
	dragXOY = e => {
		if (!mouseDown) return
		const { offsetLeft, offsetTop } = this.locateFrame.current
		let thisX = e.clientX - offsetLeft,
			thisY = e.clientY - offsetTop
		settings.O.offsetLeft += thisX - lastX
		settings.O.offsetTop += thisY - lastY
		lastX = thisX
		lastY = thisY
		reloadSettings()
	}
	freeDraw = e => {
		if (!mouseDown) return
		const { offsetLeft, offsetTop } = this.locateFrame.current
		this.props.current && this.props.current.draw([e.clientX - offsetLeft, e.clientY - offsetTop])
	}
	scaleUp = e => {
		multiple += 0.1
		settings.unit = 40 * multiple
		reloadSettings()
		this.showMagneticPoint(e)
	}

	scaleDown = e => {
		multiple -= 0.1
		if (multiple < 0.1) {
			multiple = 0.1
			message.warning('不能再小啦！')
		}
		settings.unit = 40 * multiple
		reloadSettings()
		this.showMagneticPoint(e)
	}
	handleDown = e => {
		e.preventDefault()
		const { offsetLeft, offsetTop } = this.locateFrame.current
		mouseDown = true
		wasIn = true
		lastX = e.clientX - offsetLeft
		lastY = e.clientY - offsetTop
		this.props.useFreeDrawing &&
			this.props.createANewDrawing({
				color: window.style.color,
				point: [e.clientX - offsetLeft, e.clientY - offsetTop],
			})
		this.props.useErasing && this.props.createANewErasing()
	}
	handleUp = () => {
		if (!wasIn) return
		mouseDown = false
		wasIn = false
		;(this.props.useErasing || this.props.useFreeDrawing) && this.props.current && this.props.current.endDrawing()
	}
	handleMove = e => {
		this.props.useMagneticPoint && this.showMagneticPoint(e)
		this.props.useDraging && this.dragXOY(e)
		;(this.props.useErasing || this.props.useFreeDrawing) && this.freeDraw(e)
	}
	handleEnter = () => {
		this.props.useMagneticPoint &&
			this.setState({
				show: true,
			})
	}
	handleLeave = () => {
		this.props.useMagneticPoint &&
			this.setState({
				show: false,
			})
	}
	handleClick = e => {
		!this.props.useScaling && this.props.useMagneticPoint && this.showWin()
		this.props.useScaling && this.scaleUp(e)
	}
	handleRightClick = e => {
		this.props.useScaling && this.scaleDown(e)
		e.preventDefault()
	}
	render() {
		return (
			<>
				<div
					className='locate-frame'
					style={{ width: settings.width, height: settings.height }}
					ref={this.locateFrame}
					onMouseEnter={this.handleEnter}
					onMouseLeave={this.handleLeave}
					onMouseMove={this.handleMove}
					onMouseDown={this.handleDown}
					onClick={this.handleClick}
					onContextMenu={this.handleRightClick}
				>
					<div
						className={`point ${this.state.show ? 'show' : ''}`}
						style={{ top: this.state.y + 'px', left: this.state.x + 'px' }}
					>
						<div className='point-info' style={{ transform: `scale(${this.state.winShow ? '1' : '0'})` }}>{`${backX(
							this.state.formatX
						)} , ${backY(this.state.formatY)}`}</div>
					</div>
				</div>
			</>
		)
	}
	componentDidMount() {
		document.addEventListener('mouseup', this.handleUp)
	}
}

const mapState = state => ({ ...state.canvasReducer, current: state.freeDrawingReducer.current })

export default connect(mapState, { createANewDrawing, createANewErasing })(CtrlLayer)
